<?php
// +----------------------------------------------------------------------
// | sfadmin - Suifeng Administration
// +----------------------------------------------------------------------
// | Copyright (c) 2017-2020 http://suifeng.tech All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: suifeng <1787585212@qq.com>
// +----------------------------------------------------------------------

namespace suifeng\mvc;

final class ModuleHelper
{
    /**
     * 根据模块名，返回对应的模块实例。
     *
     * @param unknown $name
     */
    public static function getInstance($name)
    {
        static $instances = null;

        if (isset($instances[$name])) {
            return $instances[$name];
        }

        $file = realpath(APP_PATH . $name . '/module.php');
        if ($file) {
            require_once $file;
            $class = '\\' . \think\App::$namespace . '\\' . $name . '\\Module';
            $instances[$name] = new $class();
        } else {
            $instances[$name] = null;
        }

        return $instances[$name];
    }

    /**
     * 注册模块所有的钩子。
     *
     * @param unknown $module
     */
    public static function regiserHooks($module)
    {
        if (is_string($module)) {
            $module = self::getInstance($module);
        }

        if ($module === null) {
            return;
        }

        $ref_class = new \ReflectionAnnotatedClass($module);
        foreach ($ref_class->getMethods() as $ref_method) {
            if ($ref_method->hasAnnotation('Hook')) {
                $hook_name = $ref_method->getAnnotation('Hook')->value;
                if (empty($hook_name)) {
                    $hook_name = $ref_method->getName();
                }

                //HookHelper::register($hook_name, array($module, $ref_method->getName()));
                \think\Hook::add($hook_name, array($module, $ref_method->getName()));
            }
        }
    }

    /**
     * 调用模块方法。如果有指定模块，则调用指定模块方法，否则调用所有模块方法。
     *
     * @param unknown $module
     * @param unknown $method
     * @param unknown $args
     */
    public static function invokeMethod($module, $method, &$args = null)
    {
        $result = null;

        if ($module !== null) {
            $module_list = [$module];
        } else {
            $module_list = array_keys(config('installed_modules'));
        }

        foreach ($module_list as $module) {
            if (is_string($module)) {
                $module = self::getInstance($module);
            }

            if ($module === null || !method_exists($module, $method)) {
                continue;
            }

            $return = $module->$method($args);

            if ($return !== null) {
                $result[] = $return;
            }
        }

        if ($module !== null) {
            return $result ? $result[0] : null;
        } else {
            return $result;
        }
    }


    /**
     * 获取安装的模块。
     */
    public static function getInstalledModules()
    {
        $installed_modules = cache('installed_modules');
        if (!$installed_modules || APP_DEBUG) {
            $installed_modules = model('admin/module')->lists();
            cache('installed_modules', $installed_modules, 3600);
        }
        return $installed_modules;
    }

    /**
     * 获取管理菜单。
     */
    public static function getAdminMenu()
    {
        $admin_menu = cache('admin_menu');
        if (!$admin_menu || APP_DEBUG) {
            $admin_menu = new \suifeng\mvc\admin\AdminMenu();
            self::invokeMethod(null, 'admin_menu', $admin_menu->root);
            $admin_menu->initialize();

            // 缓存数组，不要直接缓存对象。
            $admin_menu = $admin_menu->toArray();
            cache('admin_menu', $admin_menu, 3600);
        }
        return $admin_menu;
    }

    /**
     * 清除相关缓存。
     */
    public static function clearCache()
    {
        cache('installed_modules', null);
        cache('admin_menu', null);
    }
}